import { defineStore } from "pinia";
import { getToken, removeToken, setToken } from "../utils/token-utils";
import { ElMessage } from "element-plus";
//引入路由表
import { staticRoutes, asyncRoutes, atWillRoutes } from "@/router/routes";
//引入vue-router的类型限制
import type { RouteRecordRaw } from "vue-router";
//引入类型限制
import type { reqUserInfoReturnType, reqLoginParamType } from "@/api/userInfo";
//引入api请求
import { requestLogin, requestUserInfo, requestLogout } from "@/api/userInfo";
//引入cloneDeep
import { cloneDeep } from "lodash";
import router from "@/router";
/**
 * 用户信息
 * @methods setUserInfos 设置用户信息
 */
//定义当前state类型接口
export interface userInfoType {
  token: string;
  //userInfo的值是请求的回来的所以类型直接设置为请求的返回值类型
  userInfo: reqUserInfoReturnType;
  menuRoutes: RouteRecordRaw[];
}

//1.封装一个函数用来过滤动态路由需要展示的，接收两个参数 1.是所有动态路由 2.是请求回来的routes(当前用户可以访问的路由组件)
const filtersAsyncRoutes = (
  asyncRoutes: RouteRecordRaw[],
  reqRoutes: string[]
) => {
  //进行一个过滤，返回出用户有权限访问的路由组件
  return asyncRoutes.filter((item) => {
    //判断 使用includes方法 如果请求回来的routes包含当前动态组件 则符合条件返回为true
    if (reqRoutes.includes(item.name as string)) {
      //继续深层次的判断如果动态路由有子组件且有内容
      if (item.children && item.children.length) {
        //递归，对子组件再次进行一个处理 最后的返回值可以直接替换掉原有的子组件
        item.children = filtersAsyncRoutes(item.children, reqRoutes);
      }
      return true;
    }
  });
};
//2.封装一个函数用来把动态路由及任意路由插入到静态路由中
const addRoutes = (routes: RouteRecordRaw[]) => {
  //遍历数组中，将数组中的每一项添加到路由器中
  routes.forEach((item) => {
    router.addRoute(item);
  });
};
//3.封装一个函数用来清除动态路由
const deleteRoutes = (staticRoutes: RouteRecordRaw[]) => {
  const routers = router.getRoutes();
  //进行判断，只需要删除动态路由即可
  routers.forEach((item) => {
    if (item.name) {
      //删除当前动态组件
      router.removeRoute(item.name);
    }
  });
  //再次把静态组件插入回去
  addRoutes(staticRoutes);
};

//创建当前的userInfo小仓库
export const useUserInfoStore = defineStore("userInfo", {
  state: (): userInfoType => ({
    token: getToken() as string,
    userInfo: {
      routes: [],
      buttons: [],
      roles: [],
      name: "",
      avatar: "",
    },
    //把静态路由表保存起来,侧边栏其实是拿到这个路由表,然后遍历生成侧边栏元素的
    menuRoutes: staticRoutes,
  }),

  actions: {
    //登录请求
    async login(loginParam: reqLoginParamType) {
      try {
        //发送请求
        const result = await requestLogin(loginParam);
        //获取到token设置到state中
        this.token = result.token;
        //设置自动登录:数据持久化
        setToken(this.token);
      } catch (e) {
        //如果请求失败则抛出一个失败的promise实例,哪里调用的登录请求,就在那里处理这个失败
        return Promise.reject(e);
      }
    },

    //获取用户信息请求
    async getInfo() {
      try {
        //发送请求
        const result = await requestUserInfo();
        //获取到当前用户信息设置到state中
        this.userInfo = result;

        //调用过滤动态路由的方法,得到一个当前用户有权访问的动态路由组件
        const userAsyncRoutes = filtersAsyncRoutes(
          cloneDeep(asyncRoutes),
          result.routes
        );

        //将动态路由和任意路由添加到路由器中
        addRoutes(userAsyncRoutes.concat(atWillRoutes));

        //修改静态路由，让菜单栏也进行更新
        this.menuRoutes = staticRoutes.concat(userAsyncRoutes, atWillRoutes);
      } catch (e) {
        return Promise.reject(e);
      }
    },

    //退出登录请求
    async logOut() {
      try {
        //发送请求
        await requestLogout();
        //调用reset()清除工作
        this.reset();
        //在退出登陆后我们需要清除路由器中保存的动态路由，同时还要保留静态路由
        deleteRoutes(staticRoutes);
      } catch (e) {
        return Promise.reject(e);
      }
    },
    reset() {
      // 清除本地存储的token
      removeToken();
      //清除当前store中的token
      this.token = "";
      // 重置用户信息表单
      this.userInfo = {
        routes: [],
        buttons: [],
        roles: [],
        name: "",
        avatar: "",
      };
    },
  },
});
